package cn.remex.core.util.secret;

import cn.remex.RemexConstants;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;

/**
 *
 * <b>AES 加密/解密[一种128位密钥补位的方式]</b><br>
 * 调用方法参见main方法，事先可以指定自己的 iv和key参数<br>
 * 注意：这是AES 的 一种，其中公开密钥16位，密钥可以不是16位；偏移量16位，否则会报错；<br>
 * 另外，本方法发的实际密钥按照128位随机填充的方式，也有其他的实现方式，会产生不同的密文，需要注意。<br>
 *
 * Created by guoqi on 2016/10/31.
 */
public class AES {
//    public static  String key = "ThisIsMyTestKey12345";
    //偏移量
    private final static  String iv  = "1qaswedzxctghuji";

    /**
     * 偏移量获取
     */
    private static IvParameterSpec getIV() throws UnsupportedEncodingException {
        return new IvParameterSpec(iv.getBytes("UTF-8"));
    }

    /**
     * 密钥生成
     */
    private static SecretKeySpec getKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        Security.addProvider(new BouncyCastleProvider());
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //防止linux下 随机生成key
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(key.getBytes());
        kgen.init(128, secureRandom);
        SecretKey keygen = kgen.generateKey();
        return new SecretKeySpec(keygen.getEncoded(), "AES");
    }

    /**
     * 解密
     * @param content 密文
     * @param key 钥匙
     * @return
     */
    public static String decrypt(String content,String key) {
        Assert.notNullAndEmpty(content, ServiceCode.FAIL,"内容错误！");
        Assert.notNullAndEmpty(key, ServiceCode.FAIL,"钥匙错误！");
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, getKey(key), getIV());
            byte[] decodedContent    = new BASE64Decoder().decodeBuffer(content);
            byte[] original = cipher.doFinal(decodedContent);
            return new String(original);
        } catch (Exception e) {
            RemexConstants.logger.error("AES解密错误！{}", e);
        }
        return null;
    }

    /**
     * 加密
     * @param content 内容
     * @param key 钥匙
     * @return
     */
    public static String encrypt(String content,String key) {
        Assert.notNullAndEmpty(content, ServiceCode.FAIL,"内容错误！");
        Assert.notNullAndEmpty(key, ServiceCode.FAIL,"钥匙错误！");
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, getKey(key), getIV());
            byte[] contentByte = content.getBytes("UTF-8");
            byte[] result = cipher.doFinal(contentByte);
            return new BASE64Encoder().encode(result);
        } catch (Exception e) {
            RemexConstants.logger.error("AES加密错误！{}", e);
        }
        return null;
    }


//    /**
//     * 调用的测试主方法
//     * @param args
//     */
//    public static void main(String[] args){
//        String content = "欲穷千里目，更上一层楼";
//        String key ="ThisIsMyTestKey12345ThisIsMyTestKey12345ThisIsMyTestKey12345ThisIsMyTestKey12345ThisIsMyTestKey12345ThisIsMyTestKey12345";
//        // 加密
//        System.out.println("加密前：" + content);
//        String resultString = AES.encrypt(content,key);
//        System.out.println("加密后：" + resultString);
//        // 解密
//        String decryptResult = AES.decrypt(resultString,key);
//        System.out.println("解密后：" + decryptResult);
//
//    }

}
